package com.android.GernerateKeySet;

import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class CAServer {
	public static final int CAServerPort = 10001;
	public static final int CAServerFilePort = 10008;
	public static void main(String[] args) throws Exception {
		try {
			ServerSocket server = new ServerSocket(10001); // 포트(10001)를 열고
															// 기다린다...
			System.out.println("접속을 기다립니다.");

			while (true) {
				Socket sock = server.accept(); // 입력받은 클라이언트의 소켓을 생성한다...
				CAThread echothread = new CAThread(sock); // 사용자의 정의 클래스
															// EchoThread
				echothread.start(); // 쓰레드를 돌린다..
			} // while
		} catch (Exception e) {
			System.out.println(e);
		}
	} // main
}

class CAThread extends Thread { // 쓰레드구현을 위해 쓰레드를 상속..
	private Socket socket;
	public CAThread(Socket socket) { // 생성자 구현..
		this.socket = socket;
	}

	public void run() {
		try {
			/*
			 * CA key
			 */
			Security.addProvider(new BouncyCastleProvider());
			RSAPublicKeySpec caPubKeySpec = new RSAPublicKeySpec(
					new BigInteger(
							"b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5",
							16), new BigInteger("11", 16));

			RSAPrivateCrtKeySpec caPrivKeySpec = new RSAPrivateCrtKeySpec(
					new BigInteger(
							"b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5",
							16),
					new BigInteger("11", 16),
					new BigInteger(
							"92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619",
							16),
					new BigInteger(
							"f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03",
							16),
					new BigInteger(
							"b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947",
							16),
					new BigInteger(
							"1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5",
							16),
					new BigInteger(
							"6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded",
							16),
					new BigInteger(
							"dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339",
							16));

			/** set up the keys **/
			KeyFactory fact = KeyFactory.getInstance("RSA", "BC");
			PrivateKey caPrivKey = fact.generatePrivate(caPrivKeySpec);
			PublicKey caPubKey = fact.generatePublic(caPubKeySpec);

			InetAddress inetaddr = socket.getInetAddress(); // 접속된 소켓의 ip주소값을
															// 가져온다..
			System.out.println(inetaddr.getHostAddress() + " 로 부터 접속하였습니다."); // 호스트주소값을
			System.out.println("대기중");
			Object obj;
			ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
			
			while ((obj = ois.readObject()) == null) {
				;
			}
			if (obj.getClass() == UserInformation.class) {
				System.out.println("requestIssueClientCert");
				UserInformation userInfo = (UserInformation) obj;
				X509Certificate cert;
				cert = AttrCertExample.createClientCert(userInfo, caPrivKey,
						caPubKey);
				FileOutputStream fos = new FileOutputStream("ClientCert.der");
				fos.write(cert.getEncoded());
				fos.close();
				System.out.println("client인증서생성완료");
				FileSendThread fst = new FileSendThread("ClientCert.der",
						CAServer.CAServerFilePort);
				fst.run();
				System.out.println("client인증서 전송완료");
			} else if (obj.getClass() == String.class) {
				System.out.println("requestServerCert");
				String msg = (String) obj;
				System.out.println(msg);

				X509Certificate serverCert = AttrCertExample
						.createAcIssuerCert(caPubKey, caPrivKey);
				FileOutputStream fos = new FileOutputStream("CACert.der");
				fos.write(serverCert.getEncoded());
				fos.close();
				System.out.println("CA인증서생성완료");
				FileSendThread fst = new FileSendThread("CACert.der",
						CAServer.CAServerFilePort);
				fst.run();
				
				System.out.println("CA인증서 전송완료");
			}
		} catch (Exception ex) {
			System.out.println(ex);
		}
	} // run
}
